package LRUCache;

import java.util.HashMap;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: ling
 * Date: 2022-11-28
 * Time: 21:57
 */

public class MyLRUCache {
    static class DLinkNode {
        public int key;
        public int val;
        public DLinkNode prev;
        public DLinkNode next;
        public DLinkNode() {}
        public DLinkNode(int key,int val) {
            this.key = key;
            this.val = val;
        }

        @Override
        public String toString() {
            return " { " +
                    "key=" + key +
                    ", val=" + val +
                    "}";
        }
    }
    public DLinkNode head;//双向链表的头结点
    public DLinkNode tail;//双向链表的尾结点
    public int usedSize;//代表当前双向链表中，有效数据的个数
    public Map<Integer,DLinkNode> cache;//定义一个map
    public int capacity;//容量
    public MyLRUCache(int capacity) {
        this.head = new DLinkNode();
        this.tail = new DLinkNode();
        head.next = tail;
        tail.prev = head;
        cache = new HashMap<>();
        this.capacity = capacity;

    }
    public void put(int key,int val) {
        //1.查找当前这个key，是不是存储过
        DLinkNode node = cache.get(key);
        //2.如果没有存储过
        if(node == null) {
            //2.1需要实例化一个节点
            node = new DLinkNode(key,val);
            //2.2存储到map当中一份
            cache.put(key,node);
            //2.3把该节点存储到链表的尾巴
            addToTail(node);
            this.usedSize++;
            //2.4检查当前双向链表的有效数据个数，是不是超过了capacity
            if(this.usedSize>this.capacity) {
                //2.5超过了，就需要移除头部节点
                DLinkNode remNode = removeHead();
                //2.6清除cache中的元素
                cache.remove(remNode.key);
                //2.7 usedSize--;
                this.usedSize--;
            }
            printNodes("put");
        } else {
            //3.如果存储过
            //3.1更新这个key对应的value
            node.val = val;
            //3.2然后将该节点，移动至尾巴出【因为这个是新插入的数据】
            moveToTail(node);

        }

    }

    /**
     * 将节点添加到尾巴
     * @param node
     */
    private void addToTail(DLinkNode node) {
        tail.prev.next = node;
        node.prev = tail.prev;
        node.next = tail;
        tail.prev = node;
    }

    /**
     * 移除头部节点
     * @return
     */
    private DLinkNode removeHead() {
        DLinkNode del = this.head.next;
        head.next = del.next;
        del.next.prev = head;
        return del;
    }

    /**
     * 将节点放到尾巴
     * @param node
     */
    private void moveToTail(DLinkNode node) {
        //1.将节点删除
        removeNode(node);
        //2.将节点添加到尾巴
        addToTail(node);
    }

    /**
     * 删除指定节点
     * @param node
     */
    private void removeNode(DLinkNode node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    /**
     * 访问当前的key
     * @param key
     * @return
     */
    public int get(int key) {
        DLinkNode node = cache.get(key);
        if(node ==null) {
            return -1;
        }
        //把最近使用放到链表尾巴
        moveToTail(node);
        return node.val;
    }
    public void printNodes(String str) {
        System.out.println(str+": ");
        DLinkNode node = head.next;
        while(node!=tail) {
            System.out.println(node);
            node = node.next;
        }
    }

    public static void main(String[] args) {
        MyLRUCache lruCache = new MyLRUCache(3);
        lruCache.put(100,10);
        lruCache.put(110,11);
        lruCache.put(120,12);
        lruCache.put(120,12);
        System.out.println("获取元素");
        System.out.println(lruCache.get(110));
        lruCache.printNodes("put");

    }
}
